package com.budwk.app.sys.services.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.budwk.app.base.gmpass.SM2Util;
import com.budwk.app.base.gmpass.SM4Util;
import com.budwk.app.common.config.AppException;
import com.budwk.app.exception.ServiceException;
import com.budwk.app.exception.SqfwExceptionCodeEnum;
import com.budwk.app.popo.service.PopoInterfaceService;
import com.budwk.app.sms.service.OpaSmsService;
import com.budwk.app.sqfw.component.CommonComponent;
import com.budwk.app.sqfw.services.SqfwPoUserService;
import com.budwk.app.sqfwV2.dto.vo.SummaryQueryReqVo;
import com.budwk.app.sys.bo.SysUserDownloadBO;
import com.budwk.app.sys.dto.SysUnitUpdateDTO;
import com.budwk.app.sys.dto.SysUserForAdminDTO;
import com.budwk.app.sys.enums.SysUnitType;
import com.budwk.app.sys.models.*;
import com.budwk.app.sys.services.*;
import com.budwk.app.sys.vo.SysUserAreaVO;
import com.budwk.app.sys.vo.SysUserVO;
import com.budwk.app.util.poiUtils.SqfwInfoDataEasyExcelListener;
import com.budwk.starter.common.constant.GlobalConstant;
import com.budwk.starter.common.constant.RedisConstant;
import com.budwk.starter.common.exception.BaseException;
import com.budwk.starter.common.page.Pagination;
import com.budwk.starter.common.result.Result;
import com.budwk.starter.common.result.ResultCode;
import com.budwk.starter.common.utils.PwdUtil;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.budwk.starter.security.utils.SecurityUtil;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.async.Async;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlCallback;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.lang.random.R;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.TempFile;
import org.nutz.plugins.wkcache.annotation.CacheDefaults;
import org.nutz.plugins.wkcache.annotation.CacheRemove;
import org.nutz.plugins.wkcache.annotation.CacheRemoveAll;
import org.nutz.plugins.wkcache.annotation.CacheResult;

import java.math.BigInteger;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * @author wizzer@qq.com
 */
@IocBean(args = {"refer:dao"})
@CacheDefaults(cacheName = RedisConstant.WKCACHE + "shequ.sys_user", isHash = false, cacheLiveTime = RedisConstant.WKCACHE_TIMEOUT)
@Slf4j
public class SysUserServiceImpl extends BaseServiceImpl<Sys_user> implements SysUserService {
    public SysUserServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private SysRoleService sysRoleService;

    @Inject
    private SysMenuService sysMenuService;

    @Inject
    private SysAppService sysAppService;

    @Inject
    private SysUnitService sysUnitService;

    @Inject
    private SysUserSecurityService sysUserSecurityService;

    @Inject
    private SysUserPwdService sysUserPwdService;

    @Inject
    private RedisService redisService;

    @Inject
    private PopoInterfaceService popoInterfaceService;

    @Inject
    private SqfwPoUserService sqfwPoUserService;

    @Inject
    private OpaSmsService opaSmsService;

    @Inject
    private SysUserService sysUserService;

    @Inject
    private SysRoleUserService sysRoleUserService;

    @Inject
    private SysLogService sysLogService;

    @Override
    public Sys_user_security getUserSecurity() {
        return sysUserSecurityService.getWithCache();
    }

    @Override
    @CacheResult(cacheKey = "${userId}_getPermissionList")
    public List<String> getPermissionList(String userId) {
        Sys_user user = this.fetch(userId);
        if (user == null) {
            return new ArrayList<>();
        }
        this.fetchLinks(user, "roles");
        if (user.getRoles() == null) {
            return new ArrayList<>();
        }
        List<String> permissionList = new ArrayList<String>();
        for (Sys_role role : user.getRoles()) {
            if (!role.isDisabled()) {
                permissionList.addAll(sysRoleService.getPermissionList(role));
            }
        }
        // 追加public公共角色权限
        permissionList.addAll(sysRoleService.getPermissionList(sysRoleService.fetch(Cnd.where("code", "=", "public"))));
        return permissionList;
    }

    @Override
    @CacheResult(cacheKey = "${userId}_getRoleList")
    public List<String> getRoleList(String userId) {
        Sys_user user = this.fetch(userId);
        if (user == null) {
            return new ArrayList<>();
        }
        this.fetchLinks(user, "roles");
        if (user.getRoles() == null) {
            return new ArrayList<>();
        }
        List<String> roleList = new ArrayList<String>();
        for (Sys_role role : user.getRoles()) {
            if (!role.isDisabled()) {
                roleList.add(role.getCode());
            }
        }
        // 追加public公共角色权限
        roleList.add("public");
        return roleList;
    }

    @Override
    @CacheResult(cacheKey = "${userId}_getMenuList")
    public List<Sys_menu> getMenuList(String userId) {
        Sql sql = Sqls.create("select distinct a.* from shequ.sys_menu a,shequ.sys_role_menu b where a.id=b.menuId and " +
                " (b.roleId=@pubRoleId or b.roleId in(select c.roleId from shequ.sys_user_role c,shequ.sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) ) and a.disabled=@f order by a.location ASC,a.path asc");
        sql.params().set("pubRoleId", sysRoleService.getPublicId());
        sql.params().set("userId", userId);
        sql.params().set("f", false);
        return sysMenuService.listEntity(sql);
    }

    @Override
    @CacheResult(cacheKey = "${userId}_${appId}_getMenuList")
    public List<Sys_menu> getMenuList(String userId, String appId) {
        Sql sql = Sqls.create("select distinct a.* from shequ.sys_menu a,shequ.sys_role_menu b where a.appId=@appId and a.id=b.menuId and " +
                " (b.roleId=@pubRoleId or b.roleId in(select c.roleId from shequ.sys_role_user c,shequ.sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) ) and a.disabled=@f order by a.location ASC,a.path asc");
        sql.params().set("pubRoleId", sysRoleService.getPublicId());
        sql.params().set("userId", userId);
        sql.params().set("appId", appId);
        sql.params().set("f", false);
        return sysMenuService.listEntity(sql);
    }

    @Override
    @CacheResult(cacheKey = "${userId}_getAppList")
    public List<Sys_app> getAppList(String userId) {
        Sql sql = Sqls.create("select distinct a.id,a.name,a.path,a.hidden,a.disabled,a.location from shequ.sys_app a,shequ.sys_role_app b where a.id=b.appId and " +
                " (b.roleId=@pubRoleId or b.roleId in(select c.roleId from shequ.sys_role_user c,shequ.sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) ) and a.disabled=@f order by a.location");
        sql.params().set("pubRoleId", sysRoleService.getPublicId());
        sql.params().set("userId", userId);
        sql.params().set("f", false);
        return sysAppService.listEntity(sql);
    }

    @Override
    public List<Sys_menu> getMenusAndDatas(String userId, String appId) {
        Sql sql = Sqls.create("select distinct a.* from shequ.sys_menu a,shequ.sys_role_menu b where a.id=b.menuId and a.appId=@appId and " +
                " b.roleId in(select c.roleId from shequ.sys_role_user c,shequ.sys_role d where c.roleId=d.id and c.userId=@userId and d.disabled=@f) and a.disabled=@f order by a.location ASC,a.path asc");
        sql.params().set("userId", userId);
        sql.params().set("appId", appId);
        sql.params().set("f", false);
        return sysMenuService.listEntity(sql);
    }

    @Override
    public void checkLoginName(String loginName) throws BaseException {
        if (this.count(Cnd.where("loginname", "=", loginName)) < 1) {
            throw new ServiceException(SqfwExceptionCodeEnum.USER_NOT_EXIST.getCode(), "账号尚未获得授权,请联系街道管理员获得授权");
        }
    }

    @Override
    public void checkMobile(String mobile) throws BaseException {
        if (this.count(Cnd.where("mobile", "=", mobile)) < 1) {
            throw new ServiceException(SqfwExceptionCodeEnum.USER_NOT_EXIST.getCode(), "账号尚未获得授权,请联系街道管理员获得授权");
        }
    }

    @Override
    public void checkPwdTimeout(String userId, Long pwdResetAt) throws BaseException {
        Sys_user_security security = sysUserSecurityService.getWithCache();

        BigInteger threeSixty = BigInteger.valueOf(security.getPwdTimeoutDay());
        BigInteger eightSixtyFour = BigInteger.valueOf(86400);
        BigInteger tenThousand = BigInteger.valueOf(1000);
        BigInteger pwdresetat = BigInteger.valueOf(pwdResetAt);
        BigInteger result = threeSixty.multiply(eightSixtyFour).multiply(tenThousand);
        BigInteger resultNew = pwdresetat.add(result);
        BigInteger systemmillis = BigInteger.valueOf(System.currentTimeMillis());
        if (security != null && security.getHasEnabled() && security.getPwdTimeoutDay() > 0 && pwdResetAt != null) {
            if (systemmillis.compareTo(resultNew) > 0) {
                throw new BaseException("密码已过期，请及时修改");
            }
        }
    }

    @Override
    public void checkPassword(Sys_user user, String pwd) throws BaseException {
        Sys_user_security security = sysUserSecurityService.getWithCache();
        if (security != null && security.getHasEnabled()) {
            if (Strings.sNull(pwd).length() < security.getPwdLengthMin()) {
                throw new BaseException("密码最小长度为" + security.getPwdLengthMin());
            }
            if (Strings.sNull(pwd).length() > security.getPwdLengthMax()) {
                throw new BaseException("密码最大长度为" + security.getPwdLengthMax());
            }
            // 密码必须同时包含字母和数字，可以含特殊字符
            if (1 == security.getPwdCharMust()) {
                String regex = "^(?![0-9]+$)(?![a-zA-Z]+$)(?!\\W+$)(?![0-9\\W]+$)(?![a-zA-Z\\W]+$)[0-9A-Za-z\\W]*$";
                if (!pwd.matches(regex)) {
                    throw new BaseException("密码必须同时包含字母和数字");
                }
            }
            // 必须同时包含大写字母、小写字母、和数字，可以含特殊字符
            if (2 == security.getPwdCharMust()) {
                String regex = "^(?![0-9]+$)(?![a-z]+$)(?![A-Z]+$)(?!\\W+$)(?![a-zA-Z]+$)(?![0-9a-z\\W]+$)(?![0-9A-Z\\W]+$)(?![a-zA-Z\\W]+$)[0-9A-Za-z\\W]*$";
                if (!pwd.matches(regex)) {
                    throw new BaseException("密码必须同时包含大写字母、小写字母、和数字");
                }
            }
            // 必须同时包含大写、小写字母、特殊字符、数字
            if (3 == security.getPwdCharMust()) {
                String regex = "^(?![A-Za-z0-9]+$)(?![a-z0-9\\W]+$)(?![A-Za-z\\W]+$)(?![A-Z0-9\\W]+$)[a-zA-Z0-9\\W]*$";
                if (!pwd.matches(regex)) {
                    throw new BaseException("密码必须同时包含大写、小写字母、特殊字符、数字");
                }
            }
            if (Strings.isNotBlank(security.getPwdCharNot())) {
                if (security.getPwdCharNot().contains("loginname") && Strings.isNotBlank(user.getLoginname()) && pwd.contains(user.getLoginname())) {
                    throw new BaseException("密码中不可包含用户名");
                }
                if (security.getPwdCharNot().contains("email") && Strings.isNotBlank(user.getEmail()) && pwd.toLowerCase().contains(user.getEmail())) {
                    throw new BaseException("密码中不可包含用户电子邮箱");
                }
                if (security.getPwdCharNot().contains("mobile") && Strings.isNotBlank(user.getEmail()) && pwd.toLowerCase().contains(user.getEmail())) {
                    throw new BaseException("密码中不可包含用户手机号码");
                }
            }
            if (security.getPwdRepeatCheck()) {
                List<Sys_user_pwd> pwdList = sysUserPwdService.query(Cnd.where("userId", "=", user.getId()));
                for (Sys_user_pwd userPwd : pwdList) {
                    if (Strings.isNotBlank(userPwd.getSalt())) {
                        String bbb = PwdUtil.getPassword(pwd, userPwd.getSalt());
                        if (userPwd.getPassword().equals(PwdUtil.getPassword(pwd, userPwd.getSalt()))) {
                            throw new BaseException("您在系统中曾经使用过此密码，请更换");
                        }
                    } else {
                        //String aaa=PwdUtil.getPassword(pwd, userPwd.getSm4PassKey());
                        String sm4pass = SM4Util.encryptEcb(userPwd.getSm4PassKey(), pwd);
                        if (userPwd.getPassword().equals(PwdUtil.getPassword(pwd, userPwd.getSm4PassKey()))) {
                            throw new BaseException("您在系统中曾经使用过此密码，请更换");
                        }
                    }
                }
            }
        }
    }

    @Override
    public Sys_user loginByPassword(String loginname, String passowrd) throws BaseException {
        Sys_user user = this.fetch(Cnd.where("loginname", "=", loginname));
        if (user == null) {
            throw new BaseException("账号尚未获得授权,请联系街道管理员获得授权");
        }
        if (user.isDisabled()) {
            throw new BaseException("用户被禁用");
        }
        if (user.isDisabledLogin() && user.getDisabledLoginAt() != null) {
            Sys_user_security security = sysUserSecurityService.getWithCache();
            // 是否临时被禁用,只判断 pwdRetryTime 值,不判断锁定账号是否启用==启用后对上次设置有效
            if (security != null && security.getHasEnabled() && security.getPwdRetryTime() > 0) {
                if (System.currentTimeMillis() > user.getDisabledLoginAt() + (security.getPwdRetryTime() * 1000)) {
                    redisService.del(RedisConstant.PRE + user.getId() + ":pwdretrynum");
                    this.update(Chain.make("disabledLogin", false).add("disabledLoginAt", null), Cnd.where("id", "=", user.getId()));
                } else {
                    throw new BaseException("禁止登录，解锁时间：" + Times.format("MM月dd HH:mm:ss", new Date(user.getDisabledLoginAt() + (security.getPwdRetryTime() * 1000))));
                }
            }
        }
        //String hashedPassword = PwdUtil.getPassword(passowrd, user.getSalt());
        String hashedPassword = "";
        if (Strings.isNotBlank(user.getSalt())) {
            hashedPassword = PwdUtil.getPassword(passowrd, user.getSalt());
        } else {
            hashedPassword = SM4Util.encryptEcb(user.getSm4PassKey(), passowrd);
        }
        if (!Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) {
            // 一天内密码错误次数超过最大重试次数锁定账号
            Sys_user_security security = sysUserSecurityService.getWithCache();
            if (security != null && security.getHasEnabled() && security.getPwdRetryLock() && security.getPwdRetryNum() > 0) {
                int errNum = Integer.parseInt(Strings.sNull(redisService.get(RedisConstant.PRE + user.getId() + ":pwdretrynum"), "0"));
                redisService.setex(RedisConstant.PRE + user.getId() + ":pwdretrynum", 86400, "" + (errNum + 1));
                // 重试次数大于配置
                if (errNum + 1 > security.getPwdRetryNum()) {
                    // 锁定账户
                    if (1 == security.getPwdRetryAction()) {
                        this.update(Chain.make("disabled", true).add("updatedAt", System.currentTimeMillis()), Cnd.where("id", "=", user.getId()));
                    }
                    // 指定时间禁止登录
                    if (2 == security.getPwdRetryAction() && security.getPwdRetryTime() > 0) {
                        this.update(Chain.make("disabledLogin", true).add("disabledLoginAt", System.currentTimeMillis()), Cnd.where("id", "=", user.getId()));
                    }
                }
            }
            throw new BaseException("密码不正确");
        }
        redisService.del(RedisConstant.PRE + user.getId() + ":pwdretrynum");
        return user;
    }


    @Override
    public Sys_user loginByPasswordNew(String loginname, String passowrd, String deviceId) throws BaseException {
        Sys_user user = this.fetch(Cnd.where("loginname", "=", loginname));
        if (user == null) {
            throw new BaseException("账号尚未获得授权,请联系街道管理员获得授权");
        }
        if (user.isDisabled()) {
            throw new BaseException("用户被禁用");
        }
        if (user.isDisabledLogin() && user.getDisabledLoginAt() != null) {
            Sys_user_security security = sysUserSecurityService.getWithCache();
            // 是否临时被禁用,只判断 pwdRetryTime 值,不判断锁定账号是否启用==启用后对上次设置有效
            if (security != null && security.getHasEnabled() && security.getPwdRetryTime() > 0) {
                if (System.currentTimeMillis() > user.getDisabledLoginAt() + (security.getPwdRetryTime() * 1000)) {
                    redisService.del(RedisConstant.PRE + user.getId() + ":pwdretrynum");
                    this.update(Chain.make("disabledLogin", false).add("disabledLoginAt", null), Cnd.where("id", "=", user.getId()));
                } else {
                    throw new BaseException("禁止登录，解锁时间：" + Times.format("MM月dd HH:mm:ss", new Date(user.getDisabledLoginAt() + (security.getPwdRetryTime() * 1000))));
                }
            }
        }
        String hashedPassword = PwdUtil.getPassword(passowrd, user.getSalt());
        if (!Strings.sNull(hashedPassword).equalsIgnoreCase(user.getPassword())) {
            // 一天内密码错误次数超过最大重试次数锁定账号
            Sys_user_security security = sysUserSecurityService.getWithCache();
            if (security != null && security.getHasEnabled() && security.getPwdRetryLock() && security.getPwdRetryNum() > 0) {
                int errNum = Integer.parseInt(Strings.sNull(redisService.get(RedisConstant.PRE + user.getId() + ":pwdretrynum"), "0"));
                redisService.setex(RedisConstant.PRE + user.getId() + ":pwdretrynum", 86400, "" + (errNum + 1));
                // 重试次数大于配置
                if (errNum + 1 > security.getPwdRetryNum()) {
                    // 锁定账户
                    if (1 == security.getPwdRetryAction()) {
                        this.update(Chain.make("disabled", true).add("updatedAt", System.currentTimeMillis()), Cnd.where("id", "=", user.getId()));
                    }
                    // 指定时间禁止登录
                    if (2 == security.getPwdRetryAction() && security.getPwdRetryTime() > 0) {
                        this.update(Chain.make("disabledLogin", true).add("disabledLoginAt", System.currentTimeMillis()), Cnd.where("id", "=", user.getId()));
                    }
                }
            }
            throw new BaseException("密码不正确");
        }


        redisService.del(RedisConstant.PRE + user.getId() + ":pwdretrynum");
        return user;
    }

    @Override
    public Sys_user loginByMobile(String mobile) throws BaseException {
        Sys_user user = this.fetch(Cnd.where("mobile", "=", mobile));
        if (user == null) {
            throw new BaseException("账号尚未获得授权,请联系街道管理员获得授权");
        }
        if (user.isDisabled()) {
            throw new BaseException("用户被禁用");
        }
        return user;
    }

    // 这里不能用缓存,因为没有 userId 没法用前缀清除,会造成缓存清除不干净
    public Sys_user getUserByLoginname(String loginname) throws BaseException {
        Sys_user user = this.fetch(Cnd.where("loginname", "=", loginname));
        if (user == null) {
            throw new BaseException("用户不存在");
        }
        return user;
    }

    @CacheResult(cacheKey = "${userId}_getUserById")
    public Sys_user getUserById(String userId) throws BaseException {
        Sys_user user = this.fetch(userId);
        if (user == null) {
            throw new BaseException("用户不存在");
        }
        return user;
    }

    public void setPwdByLoginname(String loginname, String password) throws BaseException {
        Sys_user user = this.fetch(Cnd.where("loginname", "=", loginname));
        if (user == null) {
            throw new BaseException("账号尚未获得授权,请联系街道管理员获得授权");
        }
        this.checkPassword(user, password);
        String salt = R.UU32();
        String dbpwd = PwdUtil.getPassword(password, salt);
        this.update(Chain.make("salt", salt).add("password", dbpwd).add("pwdResetAt", System.currentTimeMillis()),
                Cnd.where("loginname", "=", loginname));
        this.cacheRemove(user.getId());
        this.recordPwd(user.getId(), dbpwd, salt);
    }

    public void setPwdById(String id, String password) throws BaseException {
        Sys_user user = this.fetch(id);
        if (user == null) {
            throw new BaseException("账号尚未获得授权,请联系街道管理员获得授权");
        }
        this.checkPassword(user, password);
        String salt = R.UU32();
        String dbpwd = PwdUtil.getPassword(password, salt);
        this.update(Chain.make("salt", salt).add("password", dbpwd).add("pwdResetAt", System.currentTimeMillis()),
                Cnd.where("id", "=", id));
        this.cacheRemove(user.getId());
        this.recordPwd(user.getId(), dbpwd, salt);
    }

    public void setThemeConfig(String id, String themeConfig) {
        this.update(Chain.make("themeConfig", themeConfig), Cnd.where("id", "=", id));
        this.cacheRemove(id);// 清一下缓存
    }

    public void setLoginInfo(String userId, String ip) {
        this.update(Chain.make("loginIp", ip).add("loginAt", System.currentTimeMillis()).addSpecial("loginCount", "+1"), Cnd.where("id", "=", userId));
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public Sys_user create(Sys_user user, String[] roleIds) {
        String password = user.getPassword();
        this.checkPassword(user, password);

        String key = null;
        try {
            key = SM4Util.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String cipher = SM4Util.encryptEcb(key, password);
        user.setPassword(cipher);
        user.setSm4PassKey(key);
        user.setPassword(cipher);
        user.setSex(user.getSex() == null ? 0 : user.getSex());
        user.setLoginCount(0);
        user.setNeedChangePwd(false);
        // 后台重置密码后下次登录是否强制修改密码
        Sys_user_security security = sysUserSecurityService.getWithCache();
        if (security != null && security.getHasEnabled() && security.getPwdRepeatCheck() && security.getPwdRepeatNum() > 0) {
            user.setNeedChangePwd(true);
        }
        user.setPwdResetAt(System.currentTimeMillis());
        if (StringUtils.isNotEmpty(user.getUnitId())) {
            Sys_unit sysUnit = sysUnitService.fetch(user.getUnitId());
            user.setUnitName(sysUnit.getName());
            user.setUnitPath(sysUnit.getPath());
        }
        // 序号
        Sql sql = Sqls.create("select max(CAST(serialNo as int)) from shequ.sys_user");
        sql.setCallback(Sqls.callback.integer());
        sysUserService.dao().execute(sql);
        String serialNo = String.valueOf(sql.getInt() + 1);
        user.setSerialNo(serialNo);
        //  user.setCompanyId(sysUnitService.getMasterCompanyId(user.getUnitId()));
        Sys_user newSysUser = this.insert(user);
        if (roleIds != null) {
            for (String roleId : roleIds) {
                this.dao().insert("shequ.sys_role_user", Chain.make("id", R.UU32()).add("userId", user.getId()).add("roleId", roleId));
            }
        }
        this.recordPwd(user.getId(), cipher, key);

        return newSysUser;
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void update(Sys_user user, String[] roleIds) {
        if (Strings.isNotBlank(user.getPassword())) {
            String password = user.getPassword();
            this.checkPassword(user, password);
            String salt = R.UU32();
            String dbpwd = PwdUtil.getPassword(password, salt);
            user.setPassword(dbpwd);
            user.setSalt(salt);
        } else {
            user.setPassword(null);
            user.setSalt(null);
        }
        if (StringUtils.isNotEmpty(user.getUnitId())) {
            Sys_unit sysUnit = sysUnitService.fetch(user.getUnitId());
            user.setUnitName(sysUnit.getName());
            user.setUnitPath(sysUnit.getPath());
        }
        this.updateIgnoreNull(user);
        this.dao().clear("shequ.sys_role_user", Cnd.where("userId", "=", user.getId()));
        if (roleIds != null) {
            for (String roleId : roleIds) {
                this.dao().insert("shequ.sys_role_user", Chain.make("id", R.UU32()).add("userId", user.getId()).add("roleId", roleId));
            }
        }
        this.cacheRemove(user.getId());
    }

    @Override
    public String resetPwd(String userId) {
        boolean needChangePwd = false;
        String salt = R.UU32();
        String password = "123456";
        // 后台重置密码后下次登录是否强制修改密码
        Sys_user_security security = sysUserSecurityService.getWithCache();
        if (security != null && security.getHasEnabled() && security.getPwdRepeatCheck() && security.getPwdRepeatNum() > 0) {
            needChangePwd = true;
        }

        String key = null;
        try {
            key = SM4Util.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String cipher = SM4Util.encryptEcb(key, password);
        this.update(Chain.make("password", cipher).add("salt", null)
                .add("sm4PassKey", key).add("needChangePwd", needChangePwd), Cnd.where("id", "=", userId));
        this.cacheRemove(userId);
        this.recordPwd(userId, cipher, key);
        return password;
    }

    @Override
    public String resetPwd(String userId, String password, boolean needChangePwd) {
        this.checkPassword(this.fetch(userId), password);
        String key = null;
        try {
            key = SM4Util.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String cipher = SM4Util.encryptEcb(key, password);
        this.update(Chain.make("password", cipher).add("salt", null)
                .add("sm4PassKey", key).add("needChangePwd", needChangePwd).add("pwdresetat", new Date().getTime()), Cnd.where("id", "=", userId));
        this.cacheRemove(userId);
        this.recordPwd(userId, cipher, key);
        return password;
    }

    @Async
    public void recordPwd(String userId, String password, String salt) {
        Sys_user_security security = sysUserSecurityService.getWithCache();
        if (security != null && security.getHasEnabled() && security.getPwdRepeatCheck() && security.getPwdRepeatNum() > 0) {
            Sys_user_pwd userPwd = new Sys_user_pwd();
            userPwd.setUserId(userId);
            userPwd.setPassword(password);
            userPwd.setSm4PassKey(salt);
            userPwd.setSalt(null);
            sysUserPwdService.insert(userPwd);
            Sql sql = Sqls.create("delete from shequ.sys_user_pwd where userId=@userId and id not in(select t.id FROM (SELECT * from shequ.sys_user_pwd where userId=@userId order by createdAt desc limit $num)as t)");
            sql.setParam("userId", userId);
            sql.setVar("num", security.getPwdRepeatNum());
            sysUserPwdService.execute(sql);
        }
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void deleteUser(String userId) {
        // 记录日志
        sysLogService.insertDelLog(SecurityUtil.getUserId(), JSONObject.toJSONString(userId), Sys_user.class.getAnnotation(Table.class).value(),
                "com.budwk.app.sys.services.impl.SysUserServiceImpl.deleteUser",
                "deleteUser");
        this.dao().clear("shequ.sys_role_user", Cnd.where("userId", "=", userId));
        this.dao().clear("shequ.sys_unit_user", Cnd.where("userId", "=", userId));
        this.delete(userId);
        this.cacheRemove(userId);

        // 还需要删除系统用户泡泡关系表
        List<String> popUidList = sqfwPoUserService.deleteBySysUserId(userId);

        // 泡泡用户
        // popoInterfaceService.deletePopoUser(popUidList);

    }

    @Override
    public String importUser(List<Sys_user> userList, String password, Boolean isUpdateSupport, String userId) {
        if (userList == null || userList.size() == 0) {
            throw new BaseException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        for (Sys_user user : userList) {
            try {
                if (Strings.isNotBlank(user.getImportUnitName())) {
                    Sys_unit dbUnit = sysUnitService.fetch(Cnd.where("name", "=", Strings.trim(user.getImportUnitName())));
                    if (dbUnit != null) {
                        user.setUnitId(dbUnit.getId());
                        user.setUnitPath(dbUnit.getPath());
                    }
                }
                Sys_user dbUser = fetch(Cnd.where("loginname", "=", user.getLoginname()));
                if (dbUser == null) {
                    if (count(Cnd.where("mobile", "=", user.getMobile())) > 0) {
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、账号 " + user.getLoginname() + " 手机号已存在");
                        continue;
                    }
                    if (count(Cnd.where("email", "=", user.getEmail())) > 0) {
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、账号 " + user.getLoginname() + " Email已存在");
                        continue;
                    }
                    String salt = R.UU32();
                    String pwd = password;
                    if (Strings.isBlank(pwd)) {
                        pwd = RandomUtil.randomString(12);
                    }
                    user.setPassword(PwdUtil.getPassword(pwd, salt));
                    user.setSalt(salt);
                    user.setCreatedBy(userId);
                    this.insert(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、用户 " + user.getLoginname() + "（密码：" + pwd + "） 导入成功");
                } else if (isUpdateSupport) {
                    if (!GlobalConstant.DEFAULT_SYSADMIN_LOGINNAME.equals(user.getLoginname())) {
                        if (count(Cnd.where("mobile", "=", user.getMobile()).and("loginname", "<>", user.getLoginname())) > 0) {
                            failureNum++;
                            failureMsg.append("<br/>" + failureNum + "、账号 " + user.getLoginname() + " 手机号已存在");
                            continue;
                        }
                        if (count(Cnd.where("email", "=", user.getEmail()).and("loginname", "<>", user.getLoginname())) > 0) {
                            failureNum++;
                            failureMsg.append("<br/>" + failureNum + "、账号 " + user.getLoginname() + " Email已存在");
                            continue;
                        }
                        user.setUpdatedBy(userId);
                        this.updateIgnoreNull(user);
                        successNum++;
                        successMsg.append("<br/>" + successNum + "、账号 " + user.getLoginname() + " 更新成功");
                    } else {
                        failureNum++;
                        failureMsg.append("<br/>" + failureNum + "、账号 " + user.getLoginname() + " 系统管理员不允许操作");
                    }
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getLoginname() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getLoginname() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉， 导入成功 " + successNum + " 条，导入失败 " + failureNum + " 条，错误如下：");
            if (successNum > 0) {
                throw new BaseException(failureMsg.toString() + "<br/><br/>成功列表：" + successMsg.toString());
            } else {
                throw new BaseException(failureMsg.toString());
            }
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public String addPopoUser(String sysUserId, String loginSysUserId) {
        // 首先检查用户是否存在
        Sys_user sysUser = fetch(sysUserId);
        if (sysUser == null) return null;

        // 根据系统用户id查询是否已经存在了泡泡用户关联数据
        // String existPopoUid = sqfwPoUserService.getPopoUserIdBySysUserId(sysUserId);
        // if (StringUtils.isNotBlank(existPopoUid)) return existPopoUid;

        // 然后创建用户信息
        // String popoUid = popoInterfaceService.addPopoUser(sysUser);

        // 然后插入系统用户和泡泡用户关联信息
        // if (StringUtils.isNotBlank(popoUid)) {
        //    Sqfw_po_user sqfwPoUser = sqfwPoUserService.insertSysPopoUserRelationBySys(sysUserId, popoUid, loginSysUserId);
        //    if (sqfwPoUser != null) return sqfwPoUser.getPo_userid();
        // }

        return null;
    }

    @Override
    public List<Sys_user> getUserByIds(Set<String> userIdSet) {
        return query(Cnd.where("id", "in", userIdSet));
    }

    @Override
    public Pagination getCurCompanyUserList(String sysUserId, Integer pageNo, Integer pageSize) {
        Sys_user sysUser = getUserById(sysUserId);

        // 获取该单位下所有的子单位id
        List<String> subUnitIds = sysUnitService.getSubUnitIds(sysUser.getUnitId());

        List<String> allUnitIdList = Lists.newLinkedList(subUnitIds);
        allUnitIdList.add(sysUser.getUnitId());
        return listPage(pageNo, pageSize, Cnd.where("unitid", "in", allUnitIdList));
    }

    @Override
    public void verifySM4DeviceId(String authDeviceId, String rsaDeviceId, Sys_user user) {
        //判断设备id是否传过来
        if (Strings.isNotBlank(authDeviceId)) {
            //判断数据库设备id是否为空
            if (Strings.isNotBlank(user.getDeviceId())) {
                //设备id不为空时，使用SM4解密
                String decDeviceId = SM4Util.decryptEcb(SM4Util.DEVICE_KEY_DATA, user.getDeviceId());
                if (!decDeviceId.equals(rsaDeviceId)) {
                    // 发送短信
                    /*SmsMsgDTO smsMsgDTO = new SmsMsgDTO();
                    smsMsgDTO.setPhoneNumberSet(Sets.newHashSet(user.getLoginname()));
                    String templateStr = "您已更换新设备登录，如不是本人操作请修改密码!";
                    smsMsgDTO.setTemplateParamList(Lists.newArrayList(templateStr));
                    opaSmsService.opaSmsSendOneMessage(smsMsgDTO);*/

                    //SM4国密加密
                    String SM4DeciceId = SM4Util.encryptEcb(SM4Util.DEVICE_KEY_DATA, rsaDeviceId);
                    user.setDeviceId(SM4DeciceId);
                    this.updateIgnoreNull(user);
                }
            } else {
                //SM4国密加密
                String SM4DeciceId = SM4Util.encryptEcb(SM4Util.DEVICE_KEY_DATA, rsaDeviceId);
                user.setDeviceId(SM4DeciceId);
                this.updateIgnoreNull(user);
            }
        }
    }


    @Override
    @CacheRemove(cacheKey = "${userId}_*")
    @Async
    public void cacheRemove(String userId) {

    }

    @Override
    @CacheRemoveAll
    @Async
    public void cacheClear() {

    }

    /**
     * 查询用户表5级信息（后台管理系统）
     *
     * @param sysUserDTO
     * @return
     */
    @Override
    @CacheResult(cacheKey = "${userId}_queryAreaInfo")
    public List<SysUserAreaVO> queryAreaInfo(String userId, SysUserAreaVO sysUserDTO) {
        String sqlStr = "SELECT DISTINCT province, city, district, county, community  FROM shequ.\"sys_user\" WHERE 1 = 1";
        // 先根据用户ID查询所属辖区，再根据辖区限制查询内容
        Sys_user sysUser = sysUserService.fetch(userId);
        if (ObjectUtil.isEmpty(sysUser)) {
            return null;
        }

        StringBuffer sb = new StringBuffer();
        if (!"直属".equals(sysUser.getProvince()) && StringUtils.isNotBlank(sysUser.getProvince())) {
            if (sysUser.getProvince().contains(sysUserDTO.getProvince())) {
                sb.append(" AND province like '%").append(sysUser.getProvince()).append("%'");
            }
        }
        if (!"直属".equals(sysUser.getCity()) && StringUtils.isNotBlank(sysUser.getCity())) {
            if (sysUser.getCity().contains(sysUserDTO.getCity())) {
                sb.append(" AND city like '%").append(sysUser.getCity()).append("%'");
            }
        }
        if (!"直属".equals(sysUser.getDistrict()) && StringUtils.isNotBlank(sysUser.getDistrict())) {
            if (sysUser.getDistrict().contains(sysUserDTO.getDistrict())) {
                sb.append(" AND district like '%").append(sysUser.getDistrict()).append("%'");
            }
        }
        if (!"直属".equals(sysUser.getCounty()) && StringUtils.isNotBlank(sysUser.getCounty())) {
            if (sysUser.getCounty().contains(sysUser.getCounty())) {
                sb.append(" AND county like '%").append(sysUser.getProvince()).append("%'");
            }
        }
        if (!"直属".equals(sysUser.getCommunity()) && StringUtils.isNotBlank(sysUser.getCommunity())) {
            if (sysUser.getCommunity().contains(sysUser.getCommunity())) {
                sb.append(" AND community like '%").append(sysUser.getCommunity()).append("%'");
            }
        }

        if (ObjectUtil.isEmpty(sb)) {
            return null;
        }

        Sql sql = Sqls.create(sqlStr + sb.toString());
        sql.setCallback(new SqlCallback() {
            @Override
            public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
                ResultSetMetaData metaData = rs.getMetaData();
                int columnCount = metaData.getColumnCount();
                List<SysUserAreaVO> resultInfo = new ArrayList<SysUserAreaVO>();
                while (rs.next()) {
                    SysUserAreaVO resultUser = new SysUserAreaVO();
                    for (int i = 0; i < columnCount; i++) {
                        resultUser.setProvince(rs.getString("province"));
                        resultUser.setCity(rs.getString("city"));
                        resultUser.setDistrict(rs.getString("district"));
                        resultUser.setCounty(rs.getString("county"));
                        resultUser.setCommunity(rs.getString("community"));
                    }
                    resultInfo.add(resultUser);
                }
                return resultInfo;
            }
        });
        sysUserService.execute(sql);
        return sql.getList(SysUserAreaVO.class);
    }

    /**
     * 新建用户（后台管理系统）
     *
     * @param userDto
     * @return
     */
    @Override
    @Aop(TransAop.READ_COMMITTED)
    @CacheRemoveAll
    public Sys_user createForAdmin(SysUserForAdminDTO userDto) {
        // 记录日志
        sysLogService.insertUpdateLog(SecurityUtil.getUserId(), JSONObject.toJSONString(userDto), Sys_user.class.getAnnotation(Table.class).value(),
                "com.budwk.app.sys.services.impl.SysUserServiceImpl.createForAdmin",
                "createForAdmin");
        SysUserForAdminDTO user = new SysUserForAdminDTO();
        BeanUtil.copyProperties(userDto, user);
        if (Strings.isNotBlank(user.getProvince())
                && Strings.isNotBlank(user.getCity())
                && Strings.isNotBlank(user.getDistrict())
                && Strings.isNotBlank(user.getCounty())
                && Strings.isNotBlank(user.getCommunity())) {
            user.setProvince(user.getProvince().trim());
            user.setCity(user.getCity().trim());
            user.setDistrict(user.getDistrict().trim());
            user.setCounty(user.getCounty().trim());
            user.setCommunity(user.getCommunity().trim());
        } else {
            throw new AppException("五级区域不能为空！");
        }

        // 序号
        Sql sql = Sqls.create("select max(CAST(serialNo as int)) from shequ.sys_user");
        sql.setCallback(Sqls.callback.integer());
        sysUserService.dao().execute(sql);
        String serialNo = String.valueOf(sql.getInt() + 1);
        user.setSerialNo(serialNo);

        // 密码校验
        String password = user.getPassword();
        this.checkPassword(user, password);

        String key = null;
        try {
            key = SM4Util.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String cipher = SM4Util.encryptEcb(key, password);
        user.setPassword(cipher);
        user.setSm4PassKey(key);
        user.setPassword(cipher);
        user.setSex(user.getSex() == null ? 0 : user.getSex());
        user.setLoginCount(0);
        user.setNeedChangePwd(false);
        // 后台重置密码后下次登录是否强制修改密码
        Sys_user_security security = sysUserSecurityService.getWithCache();
        if (security != null && security.getHasEnabled() && security.getPwdRepeatCheck() && security.getPwdRepeatNum() > 0) {
            user.setNeedChangePwd(true);
        }
        user.setPwdResetAt(System.currentTimeMillis());
        String unitId = R.UU32();
        //根据新建用户信息查询单位表,单位信息不存在则新建单位记录
        Sys_unit sysUnit = sysUnitService.getUnitInfoByArea(user);
        if (ObjectUtil.isNotEmpty(sysUnit)) {
            user.setUnitId(sysUnit.getId());
        } else {
            SysUnitUpdateDTO sysUnitUpdateDTO = new SysUnitUpdateDTO();
            if (Strings.isBlank(user.getUnitName())) {
                sysUnitUpdateDTO.setName(user.getProvince() + user.getCity() + user.getDistrict() + user.getCounty() + user.getCommunity());
            } else {
                sysUnitUpdateDTO.setName(user.getUnitName());
            }
            sysUnitUpdateDTO.setProvince(user.getProvince());
            sysUnitUpdateDTO.setCity(user.getCity());
            sysUnitUpdateDTO.setDistrict(user.getDistrict());
            sysUnitUpdateDTO.setCounty(user.getCounty());
            sysUnitUpdateDTO.setCommunity(user.getCommunity());
            sysUnitUpdateDTO.setCreatedBy(SecurityUtil.getUserId());
            sysUnitUpdateDTO.setCreatedAt(new Date().getTime());
            sysUnitUpdateDTO.setType(SysUnitType.GROUP);
            sysUnitService.createCompanyExhaustive(sysUnitUpdateDTO, SecurityUtil.getUserId());
            // 查询单位信息更新用户表
            Sys_unit sysUnitNew = sysUnitService.getUnitInfoByArea(user);
            user.setUnitId(sysUnitNew.getId());
        }
        Sys_user newSysUser = this.insert(user);
        this.recordPwd(user.getId(), cipher, key);
        // 默认普通用户
        this.dao().insert("shequ.sys_role_user", Chain.make("id", R.UU32()).add("userId", user.getId()).add("roleId", "78d32d8b203a43e0af1041c5380e920c"));
        return newSysUser;
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    @CacheRemoveAll
    public void updateForAdmin(Sys_user userDto, String[] roleIds) {
        // 记录日志
        sysLogService.insertUpdateLog(SecurityUtil.getUserId(), JSONObject.toJSONString(userDto), Sys_user.class.getAnnotation(Table.class).value(),
                "com.budwk.app.sys.services.impl.SysUserServiceImpl.updateForAdmin",
                "updateForAdmin");
        Sys_user user = new Sys_user();
        BeanUtil.copyProperties(userDto, user);
        if (Strings.isNotBlank(user.getProvince())
                && Strings.isNotBlank(user.getCity())
                && Strings.isNotBlank(user.getDistrict())
                && Strings.isNotBlank(user.getCounty())
                && Strings.isNotBlank(user.getCommunity())) {
            user.setProvince(user.getProvince().trim());
            user.setCity(user.getCity().trim());
            user.setDistrict(user.getDistrict().trim());
            user.setCounty(user.getCounty().trim());
            user.setCommunity(user.getCommunity().trim());
        } else {
            throw new AppException("五级区域不能为空！");
        }

        if (Strings.isNotBlank(user.getPassword())) {
            String password = user.getPassword();
            this.checkPassword(user, password);
            String salt = R.UU32();
            String dbpwd = PwdUtil.getPassword(password, salt);
            user.setPassword(dbpwd);
            user.setSalt(salt);
        } else {
            user.setPassword(null);
            user.setSalt(null);
        }

        //根据修改用户信息查询单位表,单位信息不存在则新建单位记录
        Sys_unit sysUnit = sysUnitService.getUnitInfoByArea(user);
        if (ObjectUtil.isNotEmpty(sysUnit)) {
            user.setUnitId(sysUnit.getId());
        } else {
            SysUnitUpdateDTO sysUnitUpdateDTO = new SysUnitUpdateDTO();
            if (Strings.isBlank(user.getUnitName())) {
                sysUnitUpdateDTO.setName(user.getProvince() + user.getCity() + user.getDistrict() + user.getCounty() + user.getCommunity());
            } else {
                sysUnitUpdateDTO.setName(user.getUnitName());
            }
            sysUnitUpdateDTO.setProvince(user.getProvince());
            sysUnitUpdateDTO.setCity(user.getCity());
            sysUnitUpdateDTO.setDistrict(user.getDistrict());
            sysUnitUpdateDTO.setCounty(user.getCounty());
            sysUnitUpdateDTO.setCommunity(user.getCommunity());
            sysUnitUpdateDTO.setCreatedBy(SecurityUtil.getUserId());
            sysUnitUpdateDTO.setCreatedAt(new Date().getTime());
            sysUnitUpdateDTO.setType(SysUnitType.GROUP);
            try {
                sysUnitService.createCompanyExhaustive(sysUnitUpdateDTO, SecurityUtil.getUserId());
            } catch (RuntimeException rex) {
            } catch (Exception ex) {
            }
            // 查询单位信息更新用户表
            Sys_unit sysUnitNew = sysUnitService.getUnitInfoByArea(user);
            user.setUnitId(sysUnitNew.getId());
        }
        user.setUpdatedBy(SecurityUtil.getUserId());
        user.setUpdatedAt(new Date().getTime());
        this.updateIgnoreNull(user);
        Sys_role_user sysRoleUser = sysRoleUserService.fetch(Cnd.where("userid", "=", user.getId()));
        if (ObjectUtil.isEmpty(sysRoleUser)) {
            // 默认普通用户
            this.dao().insert("shequ.sys_role_user", Chain.make("id", R.UU32()).add("userId", user.getId()).add("roleId", "78d32d8b203a43e0af1041c5380e920c"));
        }
    }

    @Override
    public void checkTestUsername(String phoneNo) {
        Sys_user loginUser = fetch(Cnd.where("loginname", "=", phoneNo));
        if (loginUser != null && loginUser.getUsername().contains("测1")) {
            throw new ServiceException(SqfwExceptionCodeEnum.USER_NOT_EXIST.getCode(), "测试账号不能使用验证码登录");
        }
    }

    @Override
    public Pagination listCommonUnitUser(SummaryQueryReqVo reqVo) {
        Sys_user currentUser = CommonComponent.getCurrentUser();
        // 如果单位id为空 返回当前用户信息
        if (StringUtils.isEmpty(currentUser.getUnitId())) {
            Pagination pagination = new Pagination();
            pagination.setTotalCount(1);
            pagination.setList(List.of(currentUser));
            return pagination;
        }
        Cnd cnd = Cnd.NEW();
        SqlExpressionGroup where = cnd.where();
        where.andEquals(Sys_user::getUnitId, currentUser.getUnitId());
        where.andEquals(Sys_user::getDelFlag, false);
        Pagination pagination = this.listPage(reqVo.getPageNo(), reqVo.getPageSize(), cnd);
        return pagination;
    }

    @Override
    public String uploadUserInfo(TempFile file, SysUserVO sysUserVO){
        if (file.getSize() <= 0) {
            return "文件不能为空！";
        }
        if (!(file.getFile().getName().endsWith(".xlsx") || file.getFile().getName().endsWith(".xls"))) {
            return "文件格式不正确！";
        }
        if (StringUtils.isEmpty(sysUserVO.getUnitId())) {
            return "单位参数不能为空";
        }
        Sys_unit sysUnit = sysUnitService.fetch(sysUserVO.getUnitId());
        if (null == sysUnit) {
            return "单位不存在!";
        }
        // 解析导入文件
        StringBuffer hasSB = new StringBuffer();
        StringBuffer insertSB = new StringBuffer();
        Integer failNum = 0;
        long startTime = System.currentTimeMillis();
        SqfwInfoDataEasyExcelListener<SysUserDownloadBO> listener = new SqfwInfoDataEasyExcelListener<>();
        try {
            EasyExcel.read(file.getInputStream(), SysUserDownloadBO.class, listener).headRowNumber(2).sheet(0).doReadSync();
            List<SysUserDownloadBO> data = listener.getData();
            List<Sys_user> finalData = new ArrayList<Sys_user>();
            for (SysUserDownloadBO summaryBO : data) {
                Sys_user sysUser = new Sys_user();
                BeanUtil.copyProperties(summaryBO, sysUser);
                int userCount = sysUserService.count(Cnd.where(Sys_user::getLoginname, "=", sysUser.getMobile()).and(Sys_user::getDelFlag, "=", false));
                if (userCount > 0) {
                    failNum++;
                    log.info("用户已存在：{}", sysUser.getMobile());
                    hasSB.append(", ").append(sysUser.getMobile());
                    continue;
                }
                sysUser.setCreatedBy(SecurityUtil.getUserId());
                sysUser.setCreatedAt(DateUtil.date().getTime());
                sysUser.setUnitName(sysUser.getUnitName());
                sysUser.setUnitId(sysUserVO.getUnitId());
                sysUser.setLoginname(summaryBO.getMobile());
                sysUser.setPassword(sysUserVO.getPassword());
                sysUser.setUnitName(sysUnit.getName());
                sysUser.setUnitPath(sysUnit.getPath());
                sysUser.setProvince(sysUnit.getProvince());
                sysUser.setCity(sysUnit.getCity());
                sysUser.setDistrict(sysUnit.getDistrict());
                sysUser.setCounty(sysUnit.getCounty());
                sysUser.setCommunity(sysUnit.getCommunity());
                sysUser.setUserLevel("0");
                sysUser.setRemark("导入数据");
                sysUser.setDelFlag(false);
                this.create(sysUser, sysUserVO.getRoleIds());
            }
            int importNum = listener.getData().size();
            if (0 < importNum) {
                insertSB.append("成功导入数据 " + (importNum - failNum) + " 条");
            } else {
                return "无有效数据导入";
            }
        } catch (Exception e) {
            log.error("导入异常： {}", e.getMessage());
        } finally {
            listener.clear();
        }
        if (StringUtils.isNotEmpty(hasSB)) {
            insertSB.append(hasSB).append(" 已存在不能创建!");
        }
        return insertSB.toString();
    }

    @Override
    public void resetPwdForAdmin(String rsaKey, String operaterPwd, String newPwd, String userId) {
        // 1.检查操作者密码是否是当前登录密码
        String str = redisService.get(RedisConstant.PRE + "ucenter:rsa:" + rsaKey);
        if (Strings.isBlank(str)) {
            throw new BaseException("RSA密钥获取失败");
        }
        NutMap nutMap = Json.fromJson(NutMap.class, str);
        RSA rsa = new RSA(nutMap.getString("privateKey"), nutMap.getString("publickKey"));
        String rsaOperaterPwd = rsa.decryptStr(operaterPwd, KeyType.PrivateKey);
        String rsaNewPwd = rsa.decryptStr(newPwd, KeyType.PrivateKey);

        Sys_user sysUser = this.fetch(SecurityUtil.getUserId());
        if (null == sysUser) {
            throw new AppException(ResultCode.USER_NOT_FOUND.getMsg());
        }
        String hashedPassword = "";
        if (Strings.isNotBlank(sysUser.getSalt())) {
            hashedPassword = PwdUtil.getPassword(rsaOperaterPwd, sysUser.getSalt());
        } else {
            hashedPassword = SM4Util.encryptEcb(sysUser.getSm4PassKey(), rsaOperaterPwd);
        }
        if (!Strings.sNull(hashedPassword).equalsIgnoreCase(sysUser.getPassword())) {
            throw new AppException("操作账号密码错误，请确认！");
        }
        // 2. 修改密码
        String key = null;
        try {
            key = SM4Util.generateKey();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String cipher = SM4Util.encryptEcb(key, rsaNewPwd);
        this.update(Chain.make("password", cipher).add("salt", null)
                .add("sm4PassKey", key).add("needChangePwd", false), Cnd.where("id", "=", userId));
        this.cacheRemove(userId);
        this.recordPwd(userId, cipher, key);
    }
}
